home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / bin / dh_pycentral < prev    next >
Text File  |  2009-10-11  |  26KB  |  806 lines

  1. #!/usr/bin/perl -w
  2.  
  3. =head1 NAME
  4.  
  5. dh_pycentral - use the python-central framework to handle Python modules and extensions
  6.  
  7. =cut
  8.  
  9. use strict;
  10. use File::Find;
  11. use Debian::Debhelper::Dh_Lib;
  12.  
  13. =head1 SYNOPSIS
  14.  
  15. B<dh_pycentral> [S<I<debhelper options>>] [B<-n>] [B<-X>I<item>] [B<-V> I<version>] [S<I<module dirs ...>>]
  16.  
  17. =head1 DESCRIPTION
  18.  
  19. dh_pycentral is a debhelper program that will scan your package, detect
  20. public Python modules and move them in /usr/share/pycentral so that
  21. python-central can byte-compile those for all supported Python versions.
  22. Extensions are kept into the original installation location.
  23.  
  24. Moving the files to the pycentral location and adding symbolic links to
  25. /usr/lib/pythonX.Y/*-packages can be done by setting the environment
  26. varibale DH_PYCENTRAL to a string containing the string B<include-links>.
  27.  
  28. Moving the files to the pycentral location can be disabled by setting
  29. the environment varibale DH_PYCENTRAL to a string containing the
  30. string B<nomove>.
  31.  
  32. #To shorten the time of unavailabilty of files during unpack and
  33. #configure, dh_pycentral does the symlinking in the preinst and does
  34. #not remove the symlinked files on upgrade. This can be disabled by
  35. #setting the environment varibale DH_PYCENTRAL to a string containing
  36. #the string B<noprepare>. If the newer version of a package needs to
  37. #remove the symlinked files on upgrade, either the package needs to
  38. #take care of the removal by calling B<pycentrel pkgremove> in the new
  39. #preinst, or leaving a file /var/lib/pycentral/<package>.pkgremove and
  40. #using pycentral 0.6.7 or later for the old package version.
  41.  
  42. The functionality to shorten the time of unavailabilty of files during
  43. unpack and configure has been removed (symlinking files in the preinst
  44. and not removing the symlinked files on upgrade) in version 0.6.9.
  45.  
  46. You must have filled the XS-Python-Version header to indicate the
  47. set of python versions that are going to be supported. dh_pycentral
  48. expects the XB-Python-Version for each binary package it is supposed
  49. to work on.
  50.  
  51. dh_pycentral will also generate substitution variables: the
  52. ${python:Provides} variable will contain versioned provides of the package
  53. (if the package's name starts with "python-"). A python-foo package could
  54. provide "python2.3-foo" and "python2.4-foo" at the same time. Python
  55. extensions have to provide those whereas it's only option for pure python
  56. modules.
  57.  
  58. The ${python:Versions} variable should be used to provide the required
  59. XB-Python-Version field listing the python versions supported by the
  60. package.
  61.  
  62. =head1 OPTIONS
  63.  
  64. =over 4
  65.  
  66. =item I<module dirs>
  67.  
  68. If your package installs python modules in non-standard directories, you
  69. can make dh_pycentral check those directories by passing their names on the
  70. command line. By default, it will check /usr/lib/$PACKAGE, /usr/share/$PACKAGE,
  71. /usr/lib/games/$PACKAGE, /usr/share/games/$PACKAGE, /usr/lib/python?.?/site-packages
  72. and /usr/lib/python?.?/dist-packages.
  73.  
  74. Note: only /usr/lib/python?.?/site-packages and the
  75. extra names on the command line are searched for binary (.so) modules.
  76.  
  77. =item B<-V> I<version>
  78.  
  79. If the .py files your package ships are meant to be used by a specific
  80. pythonX.Y version, you can use this option to specify the desired version,
  81. such as 2.3. Do not use if you ship modules in /usr/lib/site-python.
  82.  
  83. With the new policy, this option is mostly deprecated. Use the
  84. XS-Python-Field to indicate that you're using a specific python version.
  85.  
  86. =item B<-n>, B<--noscripts>
  87.  
  88. Do not modify postinst/postrm scripts.
  89.  
  90. =item B<-X>I<item>, B<--exclude=>I<item>
  91.  
  92. Exclude files that contain "item" anywhere in their filename from being
  93. taken into account to generate the python dependency. You may use this
  94. option multiple times to build up a list of things to exclude.
  95.  
  96. =back
  97.  
  98. =head1 CONFORMS TO
  99.  
  100. Python policy, version 0.4.1 (2006-06-20)
  101.  
  102. =cut
  103.  
  104. init(options => {
  105.     "no-move" => \$dh{FLAG_NO_MOVE},
  106.     "no-move" => \$dh{FLAG_NO_MOVE},
  107.     "include-links" => \$dh{FLAG_INCLUDE_LINKS},
  108. });
  109.  
  110. # extra options for pycentral debhelper call
  111. my $pcopts = "";
  112.  
  113. # required pycentral version
  114. my $pycentral_version = '0.6.11';
  115.  
  116. # format version used for the preinst script
  117. my $pyformat = '1';
  118.  
  119. my $python = 'python';
  120.  
  121. # The current python major version
  122. my $python_major;
  123. my $python_version = `$python -V 2>&1`;
  124. if (! defined $python_version || $python_version eq "") {
  125.     error("Python is not installed, aborting. (Probably forgot to Build-Depend on python.)");
  126. }
  127. elsif ($python_version =~ m/^Python\s+(\d+)\.(\d+)(\.\d+)*/) {
  128.     $python_version = "$1.$2" ;
  129.     $python_major = $1 ;
  130. } else { 
  131.     error("Unable to parse python version out of \"$python_version\".");
  132. }
  133.  
  134. # The next python version
  135. my $python_nextversion = next_minor_version($python_version);
  136. my $python_nextmajor = $python_major + 1;
  137.  
  138. my @python_allversions = ('1.5','2.1','2.2','2.3','2.4','2.5','2.6');
  139. foreach (@python_allversions) {
  140.     s/^/python/;
  141. }
  142.  
  143. # Check for -V
  144. my $usepython = "python$python_version";
  145. if($dh{V_FLAG_SET}) {
  146.     $usepython = $dh{V_FLAG};
  147.     $usepython =~ s/^/python/;
  148.     if (! grep { $_ eq $usepython } @python_allversions) {
  149.         error("Unknown python version $dh{V_FLAG}");
  150.     }
  151. }
  152.  
  153. # Cleaning the paths given on the command line
  154. foreach (@ARGV) {
  155.     s#/$##;
  156.     s#^/##;
  157. }
  158.  
  159. my $includelinks = 0;
  160. if (($ENV{DH_PYCENTRAL} && $ENV{DH_PYCENTRAL} =~ /include-links/)
  161.     || ($dh{FLAG_INCLUDE_LINKS}))
  162. {
  163.   $includelinks = 1;
  164. }
  165. if ($includelinks) {
  166.   $pcopts = "$pcopts --include-links";
  167. }
  168.  
  169. if ($ENV{DH_PYCENTRAL} && $ENV{DH_PYCENTRAL} =~ /no-?move/) {
  170.   $dh{FLAG_NO_MOVE} = 1;
  171.   $pcopts = "$pcopts --no-move";
  172. }
  173. if ($dh{FLAG_NO_MOVE}) {
  174.   $pcopts = "$pcopts --no-move";
  175. }
  176.  
  177. # Check the compatibilty mode to use
  178. my $pyversions_field = "";
  179. my $python_header = "";
  180. {
  181.     local $/ = ""; # Grab until empty line
  182.     open(CONTROL, "debian/control"); # Can't fail, dh_testdir has already been called
  183.     my $source = <CONTROL>;
  184.     close(CONTROL);
  185.     if ($source =~ m/^XS-Python-Version: \s*(.*)$/m) {
  186.         $python_header = $1;
  187.         chomp($python_header);
  188.         $pyversions_field = convert_python_header($python_header);
  189.     }
  190. }
  191.  
  192. # pyversions describes the list of python versions that this package can
  193. # work with
  194. if (-e "debian/pyversions") {
  195.     open(PYVERS, "debian/pyversions") || error("Can't open debian/pyversions: $!");
  196.     $pyversions_field = <PYVERS>;
  197.     chomp($pyversions_field);
  198.     close(PYVERS);
  199. }
  200. verbose_print("Pyversions field: $pyversions_field");
  201.  
  202. # Extract a list of officially supported Python versions
  203. my %officially_supported;
  204. if (-e "/usr/share/python/debian_defaults") {
  205.     open(DEFAULTS, "/usr/share/python/debian_defaults") ||
  206.         error("Can't open /usr/share/python/debian_defaults: $!");
  207.     foreach (<DEFAULTS>) {
  208.         if (/^supported-versions\s*=\s*(.*)$/) {
  209.             my $supported = $1;
  210.             foreach my $version (split(/\s+/, $supported)) {
  211.                 if ($version =~ /python([\d\.]+)/) {
  212.                     $officially_supported{$1} = 1;
  213.                 }
  214.             }
  215.             last;
  216.         }
  217.     }
  218.     close(DEFAULTS);
  219. }
  220.  
  221. # dependency types
  222. use constant PROGRAM   => 1;
  223. use constant PY_PRIVATE_MODULE => 2;
  224. use constant PY_PUBLIC_MODULE => 4;
  225. use constant PY_OFFICIAL_MODULE => 8;
  226. use constant PY_UNKNOWN_MODULE => 16;
  227. use constant SO_PRIVATE_MODULE => 32;
  228. use constant SO_PUBLIC_MODULE => 64;
  229. use constant SO_OFFICIAL_MODULE => 128;
  230. use constant SO_UNKNOWN_MODULE => 256;
  231.  
  232. foreach my $package (@{$dh{DOPACKAGES}}) {
  233.     my $tmp = tmpdir($package);
  234.  
  235.     # Move *.py files if needed
  236.     doit("pycentral debhelper$pcopts $package $tmp");
  237.  
  238.     # Check that we have *.py files!
  239.     my $found = 0;
  240.     find sub {
  241.         return if $File::Find::dir =~ m|^\Q$tmp\E/usr/share/doc/|;
  242.         return unless -f and /\.py$/;
  243.         $found++;
  244.     }, $tmp;
  245.  
  246.     # Here we're doing what dh_python used to do
  247.     my @dirs = ("usr/lib/$package", "usr/share/$package", "usr/lib/games/$package", "usr/share/games/$package", @ARGV );
  248.     my @dirs_so = (@ARGV);
  249.  
  250.     my $dep_on_python = 0;
  251.     my $strong_dep = 0;
  252.  
  253.     # Fail early if the package use usr/lib/site-python
  254.     if (-d "$tmp/usr/lib/site-python") {
  255.         error("The package $package puts files in /usr/lib/site-python: forbidden by policy");
  256.     }
  257.  
  258.     @dirs = grep -d, map "$tmp/$_", @dirs;
  259.     @dirs_so = grep -d, map "$tmp/$_", @dirs_so;
  260.  
  261.     my $deps = 0;
  262.     my %verdeps = ();
  263.     foreach (@python_allversions) {
  264.         $verdeps{$_} = 0;
  265.     }
  266.  
  267.     # Global scan
  268.     my $private_pydirs_regex = join('|', map { "\Q$_\E" } @dirs);
  269.     my $private_sodirs_regex = join('|', map { "\Q$_\E" } @dirs_so);
  270.     my %private_dirs_list;
  271.     my %pyversions_found;
  272.     find sub {
  273.         return unless -f;
  274.         # See if we were asked to exclude this file.
  275.         # Note that we have to test on the full filename, including directory.
  276.         my $fn="$File::Find::dir/$_";
  277.         if (excludefile($fn)) {
  278.             verbose_print("Ignoring $fn");
  279.             return;
  280.         }
  281.         # Find scripts
  282.         if (-x or /\.py$/) {
  283.             local *F;
  284.             return unless open F, $_;
  285.             if (read F, local $_, 32 and m%^#!\s*/usr/bin/(env\s+)?(python(\d+\.\d+)?)\s%) {
  286.                 verbose_print("Found program using $2: $fn");
  287.                 if ( "python" eq $2 ) {
  288.                     $deps |= PROGRAM;
  289.                 } elsif(defined $verdeps{$2}) {
  290.                     $verdeps{$2} |= PROGRAM;
  291.                 }
  292.             }
  293.             close F;
  294.         }
  295.         # Continue only with .py or .so
  296.         return unless (/\.py$/ or /\.so$/);
  297.  
  298.         # Remove any byte-compiled file
  299.         doit(("rm","-f",$_."c",$_."o")) if /\.py$/;
  300.         
  301.         # Classify the file in the right category
  302.         if (/\.py$/ and $private_pydirs_regex and $fn =~ m/(?:$private_pydirs_regex)/) {
  303.             # Private python module
  304.             verbose_print("Found private module: $fn");
  305.             my $dir;
  306.             foreach $dir (@dirs) {
  307.                 if ($fn =~ m/\Q$dir\E/) {
  308.                     $dir =~ s/^\Q$tmp\E//;
  309.                     verbose_print("Memorizing dir to byte-compile: $dir");
  310.                     $private_dirs_list{"$dir"} = 1;
  311.                 }
  312.             }
  313.             if ($dh{V_FLAG_SET}) {
  314.                 $verdeps{$usepython} |= PY_PRIVATE_MODULE;
  315.             } else {
  316.                 $deps |= PY_PRIVATE_MODULE;
  317.             }
  318.         } elsif (/\.so$/ and $private_sodirs_regex and $fn =~ m/(?:$private_sodirs_regex)/) {
  319.             # Private python extension
  320.             verbose_print("Found private extension: $fn");
  321.             if ($dh{V_FLAG_SET}) {
  322.                 $verdeps{$usepython} |= SO_PRIVATE_MODULE;
  323.             } else {
  324.                 $deps |= SO_PRIVATE_MODULE;
  325.             }
  326.         } elsif ($fn =~ m|\Q$tmp/usr/lib/python([\d\.]+)/[ds]i[st][te]-packages/|) {
  327.             $pyversions_found{$1} = 1;
  328.             my $v = $1;
  329.             if (/\.py$/) {
  330.                 verbose_print("Found public module: $fn");
  331.                 $verdeps{"python$v"} |= PY_PUBLIC_MODULE;
  332.             } else {
  333.                 verbose_print("Found public extension: $fn");
  334.                 $verdeps{"python$v"} |= SO_PUBLIC_MODULE;
  335.             }
  336.         } elsif ($fn =~ m|\Q$tmp\E/usr/lib/python([\d\.]+)/|) {
  337.             $pyversions_found{$1} = 1;
  338.             my $v = $1;
  339.             if (/\.py$/) {
  340.                 verbose_print("Found official module: $fn");
  341.                 $verdeps{"python$v"} |= PY_OFFICIAL_MODULE;
  342.             } else {
  343.                 verbose_print("Found official extension: $fn");
  344.                 $verdeps{"python$v"} |= SO_OFFICIAL_MODULE;
  345.             }
  346.         } elsif ($fn =~ m|\Q$tmp\E/usr/lib/python-support/[^/]+/python([\d\.]+)/|) {
  347.             $pyversions_found{$1} = 1;
  348.             my $v = $1;
  349.             if (/\.py$/) {
  350.                 verbose_print("Found public module: $fn");
  351.                 $verdeps{"python$v"} |= PY_PUBLIC_MODULE;
  352.             } else {
  353.                 verbose_print("Found public extension: $fn");
  354.                 $verdeps{"python$v"} |= SO_PUBLIC_MODULE;
  355.             }
  356.         } elsif ($fn =~ m{$tmp(?:/usr/share/pyshared/|/usr/share/python-support/)}) {
  357.             if (/\.py$/) {
  358.                 verbose_print("Found public module: $fn");
  359.                 $deps |= PY_PUBLIC_MODULE;
  360.             } # No extensions here
  361.         } elsif ($fn =~ m|\Q$tmp/usr/lib/python([\d\.]+)/[ds]i[st][te]-packages/|) {
  362.             
  363.         } elsif ($fn =~ m|$tmp/usr/share/doc/|) {
  364.             # Ignore .py files in doc directory
  365.         } else {
  366.             # Unknown pyfiles
  367.             if (/\.py$/) {
  368.                 verbose_print("Found unclassified module: $fn");
  369.                 if ($dh{V_FLAG_SET}) {
  370.                     $verdeps{$usepython} |= PY_UNKNOWN_MODULE;
  371.                 } else {
  372.                     $deps |= PY_UNKNOWN_MODULE;
  373.                 }
  374.             } else {
  375.                 verbose_print("Found unclassified extension: $fn");
  376.                 if ($dh{V_FLAG_SET}) {
  377.                     $verdeps{$usepython} |= SO_UNKNOWN_MODULE;
  378.                 } else {
  379.                     $deps |= SO_UNKNOWN_MODULE;
  380.                 }
  381.             }
  382.         }
  383.     }, $tmp;
  384.  
  385.     #
  386.     # NEW POLICY
  387.     #
  388.     # Generate the depends to accept all python
  389.     # versions that this package effectively provides
  390.     my ($min_version, $max_version, @versions) = analyze_pyversions($pyversions_field);
  391.     my $stop_version = "";
  392.     $stop_version = next_minor_version($max_version) if $max_version;
  393.     my $versions_field = "";
  394.     verbose_print("Pyversions analysis gives: min=$min_version, max=$max_version (@versions)");
  395.  
  396.     # Common dependency handling
  397.     foreach my $pyver (keys %verdeps) {
  398.         # Always add pythonX.Y dependency if a script uses that interpreter
  399.         if ($verdeps{$pyver} & PROGRAM) {
  400.             addsubstvar($package, "python:Depends", $pyver);
  401.         }
  402.         # Always add pythonX.Y dependency if some private modules are
  403.         # byte-compiled with it (or if extensions are
  404.         # byte-compiled with it)
  405.         if ($verdeps{$pyver} & (PY_PRIVATE_MODULE|SO_PRIVATE_MODULE)) {
  406.             addsubstvar($package, "python:Depends", $pyver);
  407.             unless ($versions_field) {
  408.                 $versions_field = $pyver;
  409.                 $versions_field =~ s/^python//;
  410.             }
  411.         }
  412.     }
  413.  
  414.     # Reset again, analysis using new policy follows
  415.     $dep_on_python = 0;
  416.  
  417.     # Private extensions, must be rebuilt for each python version
  418.     if ($deps & SO_PRIVATE_MODULE) {
  419.         if (($dh{V_FLAG_SET} and ($usepython eq "python$python_version")) or
  420.             (($min_version eq $python_version) and ($min_version eq $max_version))
  421.            ) {
  422.             # Depend on python only if the version
  423.             # used to build is the currently supported one
  424.             $dep_on_python++;
  425.         }
  426.         # Packages using a private extension can only support one
  427.         # version: if versions_field is already set that's because
  428.         # we're using -V and we should respect that, otherwise try
  429.         # the best guess:
  430.         unless($versions_field) {
  431.             if ($min_version and ($min_version eq $max_version)) {
  432.                 # Only one version supported, use it
  433.                 $versions_field = $min_version;
  434.             } elsif (compare_version($min_version, $python_version) > 0) {
  435.                 # The current version is unsupported, use the min version instead
  436.                 $versions_field = $min_version;
  437.             } else {
  438.                 # Use the current version by default
  439.                 $versions_field = $python_version;
  440.                 $min_version = $python_version;
  441.             }
  442.         }
  443.         $stop_version = next_minor_version($versions_field);
  444.     }
  445.  
  446.     # Private modules 
  447.     if ($deps & PY_PRIVATE_MODULE) {
  448.         # Package with private modules can only support one version at a time
  449.         # (even if the modules can be automatically byte-compiled for any new
  450.         # python version).
  451.         unless ($versions_field) {
  452.             # Unless min/max are the same we put "current"
  453.             if ($min_version and ($min_version eq $max_version)) {
  454.                 $versions_field = $min_version;
  455.             } elsif (compare_version($min_version, $python_version) > 0) {
  456.                 # The current version is unsupported, use the min version instead
  457.                 $versions_field = $min_version;
  458.             } else {
  459.                 # Use the current version by default
  460.                 $versions_field = "current";
  461.             }
  462.         }
  463.     }
  464.  
  465.     # Python scripts & public modules
  466.     if ($deps & (PROGRAM|PY_PUBLIC_MODULE)) {
  467.         $dep_on_python++;
  468.     }
  469.     
  470.     # Public extensions
  471.     if (scalar keys %pyversions_found) {
  472.         # Extensions will always trigger this (as well as public
  473.         # modules not handled by python-support/python-central)
  474.         $dep_on_python++;
  475.         if (scalar grep { $python_version eq $_ } keys %pyversions_found) {
  476.             # Current versions is supported by the package
  477.             # It's safe to depends on the corresponding
  478.             # interval of python versions
  479.             $min_version = min(keys %pyversions_found);
  480.             unless ($stop_version) {
  481.                 $max_version = max(keys %pyversions_found);
  482.                 $stop_version = next_minor_version($max_version);
  483.             }
  484.         } else {
  485.             # Current version is not supported by the package
  486.             if ($min_version and ($min_version eq $max_version)) {
  487.                 # If we support only one non-standard python
  488.                 # version, the depend on that version and not on python
  489.                 $dep_on_python--;
  490.                 if (! $dep_on_python) {
  491.                     addsubstvar($package, "python:Depends", "python$min_version");
  492.                 }
  493.             }
  494.         }
  495.         # Generate the Python-Version field
  496.         foreach (keys %pyversions_found) {
  497.             addsubstvar($package, "python:Versions", $_);
  498.         }
  499.         $versions_field = join(", ", keys %pyversions_found);
  500.         # Generate provides for the python2.X-foo packages that we emulate
  501.         if ($package =~ /^python-/) {
  502.             foreach (keys %pyversions_found) {
  503.                 my $virtual = $package;
  504.                 $virtual =~ s/^python-/$python$_-/;
  505.                 addsubstvar($package, "python:Provides", $virtual);
  506.             }
  507.         }
  508.     } else {
  509.         # Still try to describe the versions that the package support
  510.         $versions_field = $python_header if ($versions_field eq "current");
  511.         $versions_field = $python_header unless $versions_field;
  512.         $versions_field = "all" unless $versions_field;
  513.         addsubstvar($package, "python:Versions", $versions_field);
  514.  
  515.         # Generate provides for all python versions supported
  516.         if ($package =~ /^python-/) {
  517.             foreach (grep { $officially_supported{$_} } @versions) {
  518.                 my $virtual = $package;
  519.                 $virtual =~ s/^python-/$python$_-/;
  520.                 addsubstvar($package, "python:Provides", $virtual);
  521.             }
  522.         }
  523.     }
  524.     
  525.     if ($dep_on_python) {
  526.         # At least a script has been detected
  527.         if ($min_version) {
  528.             if (compare_version($min_version, $python_version) <= 0 ) {
  529.                 # Min-version is less or equal to current version
  530.                 addsubstvar($package, "python:Depends", $python, ">= $min_version");
  531.             } else {
  532.                 # Min version is greater to current version
  533.                 # Supposition: new stuff working only with the latest python, 
  534.                 # depend on that specific python version
  535.                 addsubstvar($package, "python:Depends", 
  536.                         "python (>= $min_version) | python$min_version");
  537.             }
  538.         }
  539.         # If a stronger dependency is needed
  540.         if ($stop_version) {
  541.             if (compare_version($stop_version, $python_version) > 0 ) {
  542.                 # Stop version is strictly bigger than current version
  543.                 addsubstvar($package, "python:Depends", $python, "<< $stop_version");
  544.             } else {
  545.                 # Only works with old versions,
  546.                 # package is mostly deprecated,
  547.                 # no need for a python dependency
  548.             }
  549.         }
  550.         # Let's depend on python anyway
  551.         addsubstvar($package, "python:Depends", $python) unless ($min_version or $stop_version);
  552.     }
  553.  
  554.     if (-d "$tmp/usr/share/pycentral") {
  555.         error("The package $package puts files in /usr/share/pycentral instead of /usr/share/pyshared; use `pycentral pycentraldir' to determine the installation directory");
  556.  
  557.     }
  558.  
  559.     if ($found or -d "$tmp/usr/share/pyshared") {
  560.         addsubstvar($package, "python:Depends", "python-central", ">= $pycentral_version");
  561.         # FIXME: move back, after $versions_field is set.
  562.         if (! $dh{NOSCRIPTS}) {
  563.             ##my $outfile = "debian/".pkgext($package)."preinst.debhelper";
  564.             ##my $savedfile = "$outfile.saved";
  565.             my $prerm_upgrade = "|upgrade";
  566.             ##if (-f $outfile) {
  567.             ##    doit(("cp","-p",$outfile,$savedfile));
  568.             ##} else {
  569.             ##    $savedfile = "";
  570.             ##}
  571.             ##autoscript($package,"preinst","preinst-pycentral","s%#PACKAGE#%$package%;s%#FORMAT#%$pyformat%;s%#PYVERSIONS#%$versions_field%;s%#PYCENTRAL_VERSION#%$pycentral_version%");
  572.             ##complex_doit("find debian/$package -mindepth 1 -regex '.*/usr/share/doc/.*' -prune -o \\( -regex '.*/usr/share/pyshared/.*' -o -regex '.*/usr/lib/python[23]\.[0-9]/[ds]i[st][te]-packages/.*' -o -name '*.py' \\) -printf '/%P=%Y\n' > $outfile.pyc");
  573.             ##complex_doit("perl -pi -e '/#PYFILES#/ and do { open F, \"$outfile.pyc\"; local \$/ ; \$_ = <F> };' $outfile");
  574.             ##doit(("mkdir","-p","-m","755","debian/$package/usr/share/pyshared-data"));
  575.             ##complex_doit("awk '/^\\[python-package\\]\$/, /^PYEOF\$/ { if (\$1 ~ /PYEOF/) exit; else print}' $outfile > debian/$package/usr/share/pyshared-data/$package");
  576.             ##doit(("chmod","644","debian/$package/usr/share/pyshared-data/$package"));
  577.             ##doit(("rm","-f","$outfile.pyc"));
  578.             ##if (!(-d "$tmp/usr/share/pyshared" || ($deps & PY_PRIVATE_MODULE)) || ($ENV{DH_PYCENTRAL} && $ENV{DH_PYCENTRAL} =~ /noprepare/)) {
  579.             ##    if ($savedfile eq "") {
  580.             ##        doit(("rm","-f","$outfile"));
  581.             ##    } else {
  582.             ##        doit(("cp","-p","$savedfile",$outfile));
  583.             ##    }
  584.             ##} else {
  585.             ##    if (!($deps & PY_PRIVATE_MODULE)) {
  586.             ##        $prerm_upgrade = "";
  587.             ##    }
  588.             ##}
  589.             ##doit(("rm","-f","$savedfile"));
  590.  
  591.             my $metafile = "debian/$package/usr/share/pyshared-data/$package";
  592.             doit(("mkdir","-p","-m","755","debian/$package/usr/share/pyshared-data"));
  593.             complex_doit("/bin/echo -e '[python-package]\nformat = $pyformat\npython-version = $versions_field\n[pycentral]\nversion = $pycentral_version\ninclude-links = $includelinks\n[files]' >> $metafile");
  594.             complex_doit("find debian/$package -mindepth 1 -regex '.*/usr/share/doc/.*' -prune -o \\( -regex '.*/usr/share/pyshared/.*' -o -regex '.*/usr/lib/python[23]\.[0-9]/[ds]i[st][te]-packages/.*' -o -name '*.py' \\) -printf '/%P=%Y\n' >> $metafile");
  595.             doit(("chmod","644","debian/$package/usr/share/pyshared-data/$package"));
  596.  
  597.             autoscript($package,"preinst","preinst-pycentral","s%#PACKAGE#%$package%");
  598.             autoscript($package,"postinst","postinst-pycentral","s%#PACKAGE#%$package%");
  599.             autoscript($package,"prerm","prerm-pycentral","s%#PACKAGE#%$package%;s%#UPGRADE#%$prerm_upgrade%");
  600.         }
  601.     }
  602. }
  603.  
  604. sub next_minor_version {
  605.     my $version = shift;
  606.     # Handles 2.10 -> 2.11 gracefully
  607.     my @items = split(/\./, $version);
  608.     $items[1] += 1;
  609.     $version = join(".", @items);
  610.     return $version;
  611. }
  612.  
  613. sub compare_version {
  614.     my ($a, $b) = @_;
  615.     my @A = split(/\./, $a);
  616.     my @B = split(/\./, $b);
  617.     my $diff = 0;
  618.     for (my $i = 0; $i <= $#A; $i++) {
  619.     $diff = $A[$i] - $B[$i];
  620.     return $diff if $diff; 
  621.     }
  622.     # They are the same
  623.     return 0;
  624. }
  625.  
  626. sub max {
  627.     my $max = shift;
  628.     foreach (@_) {
  629.     $max = $_ if (compare_version($_, $max) > 0);
  630.     }
  631.     return $max;
  632. }
  633.  
  634. sub min {
  635.     my $min = shift;
  636.     foreach (@_) {
  637.     $min = $_ if (compare_version($_, $min) < 0);
  638.     }
  639.     return $min;
  640. }
  641.  
  642. # Extract min, max and list of versions from
  643. # a string like this "-1.2,1.4-1.6,2.0,2.3-"
  644. sub analyze_pyversions {
  645.     my $field = shift;
  646.     my ($min, $max, @versions);
  647.  
  648.     my @all_versions = ("0.0");
  649.     foreach (@python_allversions) {
  650.     if (m/python([\d\.]+)/) {
  651.         push @all_versions, $1;
  652.     }
  653.     }
  654.     push @all_versions, "100.0";
  655.  
  656.     foreach my $range (split /,/, $field) {
  657.     if ($range =~ /^([\d\.]+)?-([\d\.]+)?$/) {
  658.         $min = defined($1) && $1 ? $1 : "0.0";
  659.         $max = defined($2) && $2 ? $2 : "100.0";
  660.         push @versions, grep { 
  661.         compare_version($_, $min) >= 0 and 
  662.         compare_version($_, $max) <= 0 } @all_versions;
  663.     } else {
  664.         push @versions, $range if (grep { $range eq $_ } @all_versions);
  665.     }
  666.     }
  667.  
  668.     $min = min(@versions);
  669.     $max = max(@versions);
  670.     $min = "" if (!defined($min) or $min eq "0.0");
  671.     $max = "" if (!defined($max) or $max eq "100.0");
  672.  
  673.     @versions = grep { $_ ne "0.0" and $_ ne "100.0" } @versions;
  674.  
  675.     return ($min, $max, @versions);
  676. }
  677.  
  678. # Convert the Python-Version field in a standardized "pyversions" field
  679. sub convert_python_header {
  680.     my $header = shift;
  681.     my %pyversions_expected;
  682.     my %pyversions_additional;
  683.     my $use_additional = 0;
  684.     my @all_versions = ();
  685.     foreach (@python_allversions) {
  686.     if (m/python([\d\.]+)/) {
  687.         $pyversions_additional{$1} = 1;
  688.         push @all_versions, $1;
  689.     }
  690.     }
  691.     # Add two fakes minima, maxima to check if we have limits
  692.     $pyversions_additional{"0.0"} = 1;
  693.     $pyversions_additional{"100.0"} = 1;
  694.  
  695.     # Compute the list of versions that are supported
  696.     foreach my $check (split(/,\s*/, $header)) {
  697.     if ($check =~ /^=?\s*([\d\.]+)/) {
  698.         # Add any fixed version
  699.         $pyversions_expected{$1} = 1 if (grep { $_ eq $1 } @all_versions);
  700.         next;
  701.     }
  702.     # Deactivate versions which do not match the other
  703.     # criteria
  704.     if ($check =~ /^<<\s*([\d\.]+)/) {
  705.         my $v = $1;
  706.         $use_additional = 1;
  707.         foreach (keys %pyversions_additional) {
  708.         $pyversions_additional{$_} = 0 unless (compare_version($_, $v) < 0);
  709.         }
  710.     } elsif ($check =~ /^<=\s*([\d\.]+)/) {
  711.         my $v = $1;
  712.         $use_additional = 1;
  713.         foreach (keys %pyversions_additional) {
  714.         $pyversions_additional{$_} = 0 unless (compare_version($_, $v) <= 0);
  715.         }
  716.     } elsif ($check =~ /^>=\s*([\d\.]+)/) {
  717.         my $v = $1;
  718.         $use_additional = 1;
  719.         foreach (keys %pyversions_additional) {
  720.         $pyversions_additional{$_} = 0 unless (compare_version($_, $v) >= 0);
  721.         }
  722.     }
  723.     }
  724.     if ($use_additional) {
  725.     foreach (grep { $pyversions_additional{$_} } keys %pyversions_additional) {
  726.         $pyversions_expected{$_} = 1;
  727.     }
  728.     }
  729.  
  730.     my @supported = sort { compare_version($a, $b) } 
  731.             grep { $pyversions_expected{$_} == 1 } keys %pyversions_expected;
  732.     
  733.     verbose_print("List of versions supported according to XS-Python-Version: @supported");
  734.  
  735.     # Generate the corresponding information in standardized "pyversions" format
  736.     # XXX: I go to great length to generate the shortest pyversions
  737.     # syntax but it may not be necessary for the usage that we make of it.
  738.     my ($result, $index, $range_is_open, $last_real_version) = ("", 0, 0, "");
  739.     foreach (@supported) {
  740.     if ($_ eq "0.0") {
  741.         $result .= "-"; # No lower limit
  742.         $range_is_open = 1;
  743.     } elsif ($_ eq "100.0") {
  744.         $result .= "-" unless $range_is_open; # No upper limit
  745.         $range_is_open = 0; # Proper end
  746.     } else {
  747.         $last_real_version = $_;
  748.         if ($range_is_open) {
  749.         # Range is open
  750.         if ($index <= $#all_versions and $all_versions[$index] eq $_) {
  751.             # This version still in the range
  752.         } else {
  753.             # Previous version ended the range
  754.             $result .= $all_versions[$index-1] . ",$_";
  755.             $range_is_open = 0;
  756.         }
  757.         # Find the current version in all_versions
  758.         while ($index <= $#all_versions) {
  759.             last if ($all_versions[$index] eq $_);
  760.             $index++;
  761.         }
  762.         } else {
  763.         # There's no range yet
  764.         if ($result) {
  765.             if ($index <= $#all_versions and $all_versions[$index] eq $_) {
  766.             # This version still match, we can start a range
  767.             $result .= "-";
  768.             $range_is_open = 1;
  769.             } else {
  770.             # Next version doesn't match, no range but a list
  771.             $result .= ",$_";
  772.             }
  773.         } else {
  774.             # Empty field, start with something!
  775.             $result = "$_";
  776.         }
  777.         while ($index <= $#all_versions) {
  778.             last if ($all_versions[$index] eq $_);
  779.             $index++;
  780.         }
  781.         }
  782.         $index++;
  783.     }
  784.     }
  785.     if ($range_is_open) {
  786.     # Close the range properly
  787.     $result .= $last_real_version;
  788.     }
  789.     return $result;
  790. }
  791.  
  792. =head1 SEE ALSO
  793.  
  794. L<debhelper(7)>
  795.  
  796. This program is a part of python-central but is made to work with debhelper.
  797.  
  798. =head1 AUTHORS
  799.  
  800. Raphael Hertzog <hertzog@debian.org>
  801.  
  802. Also includes bits of the old dh_python written by Josselin Mouette
  803. <joss@debian.org> who used many ideas from Brendan O'Dea <bod@debian.org>.
  804.  
  805. =cut
  806.